﻿using NPOI.SS.Formula.Functions;
using NPOI.SS.UserModel;
using NPOI.SS.Util;
using NPOI.XWPF.UserModel;
using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Reflection.Metadata.Ecma335;
using System.Security.Policy;
using System.Text;
using System.Threading.Tasks;
using static Npgsql.Replication.PgOutput.Messages.RelationMessage;
using ICell = NPOI.SS.UserModel.ICell;

namespace EasyCore.Excel
{
    public interface ISheetMapper
    {
        public bool Written { get; set; }
        public void Write();//写数据到工作簿  
    }

    public abstract class SheetMapper<T> : ISheetMapper
    {
        /// <summary>
        /// 相关的列
        /// </summary>
        public List<ColumnOption<T>> ExcelColumns { get; set; }

        /// <summary>
        /// Excel映射器
        /// </summary>
        protected ExcelMapper ExcelMapper { get; set; }

        /// <summary>
        /// 工作簿
        /// </summary>
        protected ISheet Sheet { get; set; }

        /// <summary>
        /// 工作簿名称
        /// </summary>
        public string SheetName { get; set; }



        /// <summary>
        /// 数据源
        /// </summary>
        public List<T> DataSources { get; set; }

        /// <summary>
        /// 标题行样式
        /// </summary>
        protected ICellStyle TitleCellStyle { get; set; }

        /// <summary>
        /// 数据行样式
        /// </summary>
        protected ICellStyle DataCellStyle { get; set; }

        /// <summary>
        /// 是否写入到工作簿中
        /// </summary>
        public bool Written { get; set; }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="sheetName"></param>
        /// <param name="isAutoOrder"></param>
        public SheetMapper(ExcelMapper excelMapper, string sheetName)
        {
            this.ExcelMapper = excelMapper;
            TitleCellStyle = this.ExcelMapper.GetDefaultTitleCellStyle();
            DataCellStyle = this.ExcelMapper.GetDefaultDataCellStyle(); 
            this.SheetName = sheetName;
            ExcelColumns = new List<ColumnOption<T>>();
        }

        /// <summary>
        /// 添加复合标题
        /// </summary>
        /// <param name="colName"></param>
        /// <param name="children"></param>
        /// <returns></returns>
        public ColumnOption<T> Map(string colName, List<ColumnOption<T>> children)
        {
            if (ExcelColumns == null) ExcelColumns = new List<ColumnOption<T>>();
            var columnOption = new ColumnOption<T>(colName);
            ExcelColumns.Add(columnOption);
            if (children != null && children.Any()) columnOption.Children = children;  
            return columnOption;
        }


        /// <summary>
        /// 添加标题与字段对应关系
        /// </summary>
        /// <param name="colName"></param>
        /// <param name="children"></param>
        /// <returns></returns>
        public ColumnOption<T> Map(string colName, string fieldName = null, int colWidth = 0, Func<int, T, object> colValFunc = null)
        {
            if (ExcelColumns == null) ExcelColumns = new List<ColumnOption<T>>();
            if (colWidth == 0) colWidth = this.ExcelMapper.DefaultColumnWidth;
            var columnOption = new ColumnOption<T>(colName, fieldName, colWidth, colValFunc);
            ExcelColumns.Add(columnOption);
            return columnOption;
        }

        /// <summary>
        /// 配置标题行样式
        /// </summary>
        /// <param name="cellStyleAction"></param>
        public SheetMapper<T> ConfigTitleCellStyle(Action<ICellStyle> cellStyleAction)
        {
            if (cellStyleAction == null) return this;
            TitleCellStyle = ExcelMapper.Workbook.CreateCellStyle();
            cellStyleAction(TitleCellStyle);
            return this;
        }

        /// <summary>
        /// 数据写入到工作簿中
        /// </summary>
        public void Write()
        {
            if (this.Written) return; //如果工作簿已写入文档，则不执行写入操作
            Sheet = ExcelMapper.Workbook.CreateSheet(this.SheetName);//创建工作簿
            Sheet.DefaultRowHeight = (short)(ExcelMapper.DefaultRowHeight * 20);
            Sheet.DisplayGridlines = true;
            this.Written = true;//标记文档已写入Excel
            int maxCoumnSpan;
            int maxRowSpan;
            (maxRowSpan, maxCoumnSpan) = SetTitles();//设置标题
            var leaf = GetLeafColumns(ExcelColumns);//获得叶子节点
            for (var index = 0; index < leaf.Count; index++)
            {
                Sheet.SetColumnWidth(index, leaf[index].ColumnWidth * 256); //设置列宽  
            }
            int dataRowCount = DataSources.Count();//获得数据行
            for (var index = 0; index < dataRowCount; index++)
            {
                var startRowIndex = maxRowSpan + index;
                IRow row = Sheet.CreateRow(startRowIndex); //创建行
                ICell cell;       
                for (var leafIndex = 0; leafIndex < leaf.Count; leafIndex++)
                {
                  
                    var tempLeaf = leaf[leafIndex];
                    object? cellVal = null;
                    if (tempLeaf.ColumnValFunc != null)
                    {
                        cellVal = tempLeaf.ColumnValFunc(index + 1, DataSources[index]);
                    }
                    else
                    {
                        cellVal = GetRowCell(index + 1, DataSources[index], tempLeaf);
                    }
                    cell = row.CreateCell(leafIndex);
                    cell.CellStyle = DataCellStyle; //设置数据列样式        
                    if (cellVal == null) cell.SetCellValue(string.Empty);
                    else if (cellVal is string) cell.SetCellValue(cellVal as string);
                    else cell.SetCellValue(string.Empty);
                }
            }
        }

        /// <summary>
        /// 设置标题
        /// </summary>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public (int, int) SetTitles()
        {
            if (ExcelColumns == null || !ExcelColumns.Any()) throw new Exception("未设置任何列，无法进行数据导出功能");
            var maxColSpan = 0;
            List<int> rowSpans = new List<int>();
            foreach (var item in ExcelColumns)
            {
                maxColSpan += item.GetColumnSpan();//计算总的宽度
                var rowSpan = item.GetRowSpan();
                rowSpans.Add(rowSpan);
            }
            int maxRowSpan = rowSpans.Max();//获得最大的深度
            List<IRow> rows = new List<IRow>();
            for (var index = 0; index < maxRowSpan; index++)
            {
                var row = (IRow)Sheet.CreateRow(index);
                rows.Add(row); //创建最大行数
                for (var index2 = 0; index2 < maxColSpan; index2++)
                {
                    var cell = row.CreateCell(index2);
                    cell.SetCellValue("");
                }
            }
            //遍历写标题行
            var startRowIndex = 0;
            var startColumnIndex = 0;
            foreach (var item in ExcelColumns)
            {
                startColumnIndex = WriteTitle(rows, startRowIndex, startColumnIndex, maxRowSpan, item);
            }
            return (maxRowSpan, maxColSpan);//返回最大行数
        }

        /// <summary>
        /// 获得显示数据的叶子节点
        /// </summary>
        /// <param name="leaf"></param>
        /// <param name="columns"></param>
        /// <param name="rowSpan"></param>
        /// <returns></returns>
        private List<ColumnOption<T>> GetLeafColumns(List<ColumnOption<T>> columns)
        {
            List<ColumnOption<T>> leaf = new List<ColumnOption<T>>();
            foreach (ColumnOption<T> item in columns)
            {
                if (item.Children == null || !item.Children.Any()) leaf.Add(item);
                else
                {
                    var sub = GetLeafColumns(item.Children);
                    leaf.AddRange(sub);
                }
            }
            return leaf;
        }

        /// <summary>
        /// 写入标题
        /// </summary>
        /// <param name="rows"></param>
        /// <param name="startRowIndex"></param>
        /// <param name="startColumnIndex"></param>
        /// <param name="maxRowSpan"></param>
        /// <param name="columnOption"></param>
        /// <returns></returns>
        private int WriteTitle(List<IRow> rows, int startRowIndex, int startColumnIndex, int maxRowSpan, ColumnOption<T> columnOption)
        {
            ICell cell = rows[startRowIndex].GetCell(startColumnIndex);
            cell.SetCellValue(columnOption.ColumnName);//设置列的标题
            cell.CellStyle = TitleCellStyle;//设置标题样式
            var rowSpan = columnOption.GetRowSpan(); //用于合并列
            var columnSpan = columnOption.GetColumnSpan();//用于合并行:当大于1时，代表有子项
            if (columnSpan > 1) {
                for (var index = 1; index < columnSpan; index++)
                {
                    cell = rows[startRowIndex].GetCell(startColumnIndex + index);
                    cell.CellStyle = TitleCellStyle;
                }
                Sheet.AddMergedRegion(new CellRangeAddress(startRowIndex, startRowIndex, startColumnIndex, startColumnIndex + columnSpan - 1)); //合并列与行 ：起始行 结束行，起始列，结束列
            } 
            if (rowSpan == 1 && (maxRowSpan - startRowIndex) > 1)
            {
                for (var index = startRowIndex + 1; index < maxRowSpan; index++) {
                    cell = rows[index].GetCell(startColumnIndex);
                    cell.CellStyle = TitleCellStyle;
                }
                Sheet.AddMergedRegion(new CellRangeAddress(startRowIndex, maxRowSpan - startRowIndex - 1, startColumnIndex, startColumnIndex)); //合并列
            }
            if (columnOption.Children != null && columnOption.Children.Any())
            {
                var tempStartColumnIndex = startColumnIndex;
                foreach (var item in columnOption.Children)
                {
                    tempStartColumnIndex = WriteTitle(rows, startRowIndex + 1, tempStartColumnIndex, maxRowSpan, item);
                }
            }
            return startColumnIndex + columnSpan;
        }
        

        /// <summary>
        /// 数据容器只能放一个数据源
        /// </summary>
        /// <param name="data"></param>  
        public abstract void Put(object data);

        /// <summary>
        /// 获得缺省值
        /// </summary>
        /// <param name="rowIndex"></param>
        /// <param name="row"></param>
        /// <param name="columnOption"></param>
        /// <returns></returns>
        public abstract object GetRowCell(int rowIndex, T row, ColumnOption<T> columnOption);

        /// <summary>
        /// 配置数据行样式
        /// </summary>
        /// <param name="cellStyleAction"></param>
        public SheetMapper<T> ConfigDataCellStyle(Action<ICellStyle> cellStyleAction)
        {
            if (cellStyleAction == null) return this;
            TitleCellStyle = ExcelMapper.Workbook.CreateCellStyle();
            cellStyleAction(TitleCellStyle);
            return this;
        }
    }

}
